/** @file    Timer.cpp
 *  @author  Alessandro Polo
 *  @version $Id: Timer.cpp 2829 2010-08-02 20:45:47Z alex $
 *  @brief
 * File containing methods for the wosh::Timer class.
 * The header for this class can be found in Timer.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

 #include <core/Timer.h>
 #include <core/Utilities.h> //tmp
 #include <ctime>

 #ifdef _OS_POSIX
 # include <sys/time.h> // for gettimeofday()
 #elif defined(_OS_WINxx)
 # include <windows.h> // for Windows APIs
 #endif


using namespace std;
namespace wosh {

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
 
Timer::Timer() {
	clear();
 }

Timer::~Timer() {
 }

//////////////////////////////////////////////////////////////////////////////////////////////// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Timer::clear() {
	clearStart();
	clearStop();
 }

void Timer::clearStart() {
	this->start_time.tv_sec = 0;
	this->start_time.tv_usec = 0;
	this->start_clock = 0;
 }

void Timer::clearStop() {
	this->stop_clock = 0;
	this->stop_time.tv_sec = 0;
	this->stop_time.tv_usec = 0;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////

void Timer::start() {
#ifdef _OS_POSIX
	gettimeofday((timeval*)&this->start_time, NULL);
	this->start_clock = std::clock();
#elif defined(_OS_WINxx)
	LARGE_INTEGER tickNow;
    QueryPerformanceCounter(&tickNow);
	this->start_clock = tickNow.QuadPart;
#endif
 }

void Timer::stop() {
#ifdef _OS_POSIX
	this->stop_clock = std::clock();
	gettimeofday((timeval*)&this->stop_time, NULL);
#elif defined(_OS_WINxx)
	LARGE_INTEGER tickNow;
    QueryPerformanceCounter(&tickNow);
	this->stop_clock = tickNow.QuadPart;
#endif
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////	double diff;

double Timer::getTimeSpanMicroSec() const {
#ifdef _OS_POSIX
    double startTimeInMicroSec = (this->start_time.tv_sec * 1000000.0) + this->start_time.tv_usec;
    double endTimeInMicroSec = (this->stop_time.tv_sec * 1000000.0) + this->stop_time.tv_usec;
	return endTimeInMicroSec - startTimeInMicroSec;
#elif defined(_OS_WINxx)
	LARGE_INTEGER frequency;// ticks per second
    QueryPerformanceFrequency(&frequency);
    double startTimeInMicroSec = this->start_clock * (1000000.0 / frequency.QuadPart);
    double endTimeInMicroSec = this->stop_clock * (1000000.0 / frequency.QuadPart);
	return endTimeInMicroSec - startTimeInMicroSec;
#endif
	return 0.0;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

long Timer::now_clocks() {
#ifdef _OS_WINCE
	return -1;
#else
	return std::clock();
#endif
 }
long Timer::now_epoch() {
	return Utilities::std_time();
 }

TimeMs Timer::now_time() {
	TimeMs time;
	time.tv_sec = 0;
	time.tv_usec = 0;
#ifdef _OS_POSIX
	gettimeofday((timeval*)&time, NULL);
#elif defined(_OS_WINxx)

#endif
	return time;
 }

double Timer::getTimeSpanClocksMs() const {
#ifdef _OS_POSIX
	return ( this->stop_clock - this->start_clock )*1000 / (double)CLOCKS_PER_SEC;
#elif defined(_OS_WINxx)
	return getTimeSpanMilliSec();
#endif
	return -1;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*

#ifndef _RDTSCTIMER_H_
#define _RDTSCTIMER_H_

class CRdtscTimer
{
  unsigned __int64 start, end;

  inline static unsigned __int64 _RDTSC()
  {
    _asm    _emit 0x0F
    _asm    _emit 0x31
  }

public:
  inline void Start()
  {
    start = _RDTSC();
  }
  
  inline unsigned __int64 Stop()
  {
    end = _RDTSC();
    return (end-start);
  }
};

#endif // _RDTSCTIMER_H_





//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////




#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <iostream>

using namespace std;

inline unsigned __int64 RDTSC(void)
{
  _asm  _emit 0x0F
  _asm  _emit 0x31
}

class TimerRDTSC
{
  unsigned __int64  start_cycle;
  unsigned __int64  end_cycle;

public:
  inline void Start()
  {
    start_cycle = RDTSC();
  }

  inline void Stop()
  {
    end_cycle = RDTSC();
  }

  unsigned __int64 Interval()
  {
    return end_cycle - start_cycle;
  }
};

class TimerPerformanceCounter
{
  unsigned __int64  start_time;
  unsigned __int64  end_time;

public:
  inline void Start()
  {
    QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&start_time));
  }

  inline void Stop()
  {
    QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER*>(&end_time));
  }

  unsigned __int64 Interval()
  {
    // Return duration in seconds...
    return end_time - start_time;
  }
};

template<class Timer, class Test, unsigned SleepRepeat, unsigned QuantumRepeat=1>
class ProfileSpeed
{
  unsigned __int64 test_interval;
  Timer            timer;
  Test             test;

  void QuantumTest()
  {
    unsigned i;
    Sleep(10);
    for (i=0; i < QuantumRepeat; ++i)
    {
      timer.Start();
      test.RunTest();
      timer.Stop();
      test_interval += timer.Interval();
    }
  }

public:
  ProfileSpeed() : test_interval(0) {}

  void Run()
  {
    unsigned i;
    for (i=0; i < SleepRepeat; ++i)
    {
      QuantumTest();
    }
  }

  unsigned __int64 TestInterval() {return test_interval;}
};

class HelloTest
{
public:
  inline static void RunTest()
  {
    cout << "Hello world!" << endl;
  }
};

int main(int argc, char* argv[])
{
  // Run HelloTest 50 times sleeping between each test, using TimerRDTSC
  ProfileSpeed<TimerRDTSC, HelloTest, 50> test1;

  // Run HelloTest 50 times sleeping between every 2 tests, using TimerRDTSC
  ProfileSpeed<TimerRDTSC, HelloTest, 25, 2> test2;

  // Switch test order if an argument is specified to the program
  if (argc == 1)
  {
    test1.Run();
    test2.Run();
  }
  else
  {
    test2.Run();
    test1.Run();
  }

  cout << "Test 1 Interval: " << unsigned(test1.TestInterval()) << endl;
  cout << "Test 2 Interval: " << unsigned(test2.TestInterval()) << endl;

  return 0;
}








*/

}; // namespace wosh
